﻿using NetDh.Lib;
using NetDh.Lib.Helper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NetDh.TestConsole
{
    /// <summary>
    /// 私下测试类
    /// </summary>
    public class TestMulThread
    {
        public static void TestMain()
        {
            #region comm test
            //for (int i = 0; i < 10; i++)
            //{
            //    TestAwait(i);
            //    Thread.Sleep(800);
            //}

            //TestConCurrentHttpRequest();
            //TestHttpWebRequestTimeOut();
            for (int i = 0; i < 10; i++)
            {
                TestThread(i);
                Thread.Sleep(1500);
            }
            //TestThread();
            #endregion
        }

        /// <summary>
        /// 封装Console.WriteLine，增加显示当前时间和线程Id
        /// </summary>
        /// <param name="info"></param>
        public static string Trace(string info)
        {
            string msg = string.Format("{0} ThreadId:{1} {2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), Thread.CurrentThread.ManagedThreadId, info);
            Console.WriteLine(msg);
            Debug.WriteLine(msg);
            return msg;
        }

        private static async Task<string> AsyncMethod()
        {
            Trace("AsyncMethod before");
            string result = await Task.Run(() =>
            {
                Trace("Task.Run before");
                Thread.Sleep(600);
                Trace("Task.Run after");
                return "task run return";
            });
            Trace(result);
            Trace("AsyncMethod after");
            return result;
        }

        public async static void TestAwait(int id)
        {

            Trace(id + " begin");
            var ResultTask = AsyncMethod();
            Trace(ResultTask.Result);
            /*控制台下，因为没有SynchronizationContext.Current上下文限制，因此这样写法不会死锁，
             * 而在winform(有ui context)和web(有request context)中是会死锁*/

            //var t = Task.Run(() =>
            //{
            //    Trace(id + " run..");
            //    Thread.Sleep(600);
            //    return "run return..";
            //});
            //Trace(id + " end");
            ////Trace(id + await t);
            //Trace(id + t.Result);
            //Thread.Sleep(100);
            Trace(id + " after await");
        }

        //测试并发请求时的UserToken正确性。
        public static void TestConCurrentHttpRequest()
        {
            Trace("begin");
            var rand = new Random();
            ParallelLoopResult result = Parallel.For(0, 10, i =>
            {
                for (int j = 0; j < 10; j++)
                {
                    var id = $"{i}-{j}";
                    var userToken = new UserToken() { UserId = "uid-" + id, UserType = "user", Platform = "console" };
                    var ticket = TokenHelper.GetUserTicket(userToken);
                    var postStr = JsonConvert.SerializeObject(new { id = id });//服务端[FromBody]可无可有。
                    var tokenHeader = new NameValueCollection();
                    tokenHeader.Add("token", ticket);
                    //var respStr = HttpHelper.HttpPost("http://localhost:55707/api/TestCurrentUser", postStr, tokenHeader);
                    var respStr = HttpHelper.HttpPost("http://localhost:55707/api/TestCurrentUserAsync2", postStr, tokenHeader, "application/x-www-form-urlencoded");
                    //if (respStr.StartsWith("error"))
                    Console.WriteLine($"id:{id},respStr:{respStr},threadId:{Thread.CurrentThread.ManagedThreadId}");
                    //Thread.Sleep(rand.Next(1, 10));
                }
            });
            Trace("end");
            Trace("是否完成:" + result.IsCompleted);
        }
        //测试HttpWebRequest的TimeOut、ReadWriteTimeout区别
        public static void TestHttpWebRequestTimeOut()
        {
            /*
             * Timeout设置的是从发出请求开始，到与服务器建立连接并得到第一次服务端响应的时间。
             * ReadWriteTimeout设置的是从服务端开始响应，到响应结束的时间（Read Stream过程）。或者写入请求流的时间（Write Stream过程）
             */
            try
            {
                Stopwatch watch = new Stopwatch();
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:55707/home/t4");
                request.Method = "POST";
                request.ContentType = "application/json";
                request.Timeout = 5000;
                request.ReadWriteTimeout = 2000;
                byte[] btBodys = Encoding.UTF8.GetBytes("");
                request.ContentLength = btBodys.Length;
                Stream writeStream = request.GetRequestStream();
                writeStream.Write(btBodys, 0, btBodys.Length);
                Thread.Sleep(3000);
                writeStream.Close();
                //2.请求服务端，接收HTTP做出的响应。
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                StreamReader readStream = new StreamReader(response.GetResponseStream());
                string responseContent = readStream.ReadToEnd();
                readStream.Close();
                response.Close();
                watch.Stop();
                Trace(watch.ElapsedMilliseconds + ":" + responseContent);
            }
            catch (Exception e)
            {
                Trace(e.Message);
            }
        }

        #region Task多线程测试
        //测试父线程的重复使用在子线程中。
        public static void TestThread(int id)
        {
            Trace(id + "main begin");
            var t1 = Task.Run(() =>
            {
                Trace("t1 begin");
                int i = 0;
                var tmp = new TmpClass() { Name = "t1-name" };
                var subT1 = Task.Run(() =>
                {
                    i++;
                    tmp.Name = "subT1-name";
                    Thread.Sleep(1000);
                    i++;
                    //Trace("tsubT1 end,i:" + i);
                    Trace("tsubT1 end------,i:" + i + ",tmp:" + tmp.Name);
                });
                var subT1_2 = Task.Run(() =>
                {
                    i++;
                    tmp.Name = "subT1-name";
                    Thread.Sleep(990);
                    i++;
                    Trace("subT1_2 end,i:" + i);
                    //Trace("subT1_2 end------,i:" + i + ",tmp:" + tmp.Name);
                });
                i++;
                //Task.WaitAll(subT1);
                //Thread.Sleep(30);
                //Trace("t1 end");
                /*
                 * 父线程t1中创建子线程subT1后，马上就退出为空闲状态了，是很可能被用于执行subT1的任务。
                 * 如果父线程没有马上退出，比如Sleep(30)秒，则是不会被用于子线程执行。
                 * 而如果在Sleep(30)之前增加Task.WaitAll代码，那么父线程又有可能被用于子线程执行，
                 * 原因是父线程遇到Task.WaitAll就被标记为暂时空闲了，可以执行WaitAll中的线程，但不能执行其它线程。
                 */
            });
            //模拟一个竞争线程，增加Task对线程的重复使用概率
            var t2 = Task.Run(() =>
            {
                Thread.Sleep(1000);
                //Trace("t2 end");
            });
            //Trace(id+"main end");
        }
        #endregion
    }

    class TmpClass
    {
        public string Name { get; set; }
    }
}
